package com.zkh.myutils.net.http;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.function.Function;
import java.util.zip.GZIPInputStream;

import javax.servlet.http.HttpServletRequest;

import com.zkh.myutils.io.IOUtils;
import com.zkh.myutils.io.log.Logger;
import com.zkh.myutils.utils.Assert;
import com.zkh.myutils.utils.StringUtils;
import com.zkh.myutils.utils.UtilsException;

public class HttpUtils {
	
	/**
	 * 发送请求，默认GET请求，发送和接收数据编码默认UTF-8
	 * @param url 请求地址
	 * @return
	 */
	public static String sendRequest(String url) {
		return sendRequest(url, null, false);
	}
	
	/**
	 * 发送请求，发送和接收数据编码默认UTF-8
	 * @param url 请求地址
	 * @param isSendPost 是否发送POST请求
	 * @return
	 */
	public static String sendRequest(String url, boolean isSendPost) {
		return sendRequest(url, null, isSendPost);
	}
	
	/**
	 * 发送请求，默认GET请求，发送和接收数据编码默认UTF-8
	 * @param url 请求地址
	 * @param param 参数。格式：key1=value1&key2=value2...
	 * @return
	 */
	public static String sendRequest(String url, String param) {
		return sendRequest(url, param, false);
	}
	
	/**
	 * 发送请求，发送和接收数据编码默认UTF-8
	 * @param url 请求地址
	 * @param param 参数。格式：key1=value1&key2=value2...
	 * @param isSendPost 是否发送POST请求
	 * @return
	 */
	public static String sendRequest(String url, String param, boolean isSendPost) {
		return sendRequest(new RequestParam(url, param, isSendPost));
	}

	/**
	 * 发送请求，可指定各种参数
	 * @param param 请求参数对象
	 * @return
	 */
	public static String sendRequest(RequestParam param) {
		//请求地址
		String location = param.getUrl();
		//检查空
		if(StringUtils.isEmpty(location)) {
			throw new UtilsException("请指定请求地址");
		}
		//初始化变量
		OutputStreamWriter writer = null;	//请求数据写句柄
		BufferedReader reader = null;	//响应数据读句柄
		StringBuilder sb = new StringBuilder(); //最终返回值
		//请求方式
		boolean post = "post".equalsIgnoreCase(param.getMethod());
		//关闭读写对象
		try {
			//请求参数
			String reqParam = param.getParam();
			boolean haveParam = StringUtils.isNotEmpty(reqParam);
			//get请求参数（get请求且参数不为空）
			String getParam = !post && haveParam ? ((location.contains("?") ? "&" : "?") + reqParam) : "";
			//创建URL对象
			URL url = new URL(location + getParam);
			//打印日志
			Logger.debug("发送Http请求：" + location + getParam);
			//打开和URL之间的连接
			URLConnection conn = url.openConnection();
			//设置RequestProperty属性
			param.setRequestProperty(conn);
			//如果是POST请求，则单独处理参数
			if(post) {
				// 发送POST请求必须设置如下两行
				conn.setDoOutput(true);
				conn.setDoInput(true);
				// 获取URLConnection对象对应的输出流
				writer = new OutputStreamWriter(conn.getOutputStream(), param.getSendCode());
				// 发送请求参数
				writer.write(haveParam ? reqParam : "");
				// flush输出流的缓冲
				writer.flush();
			}
			// 建立实际的连接
			conn.connect();
			/** 以下开始读取响应值 **/
			//判断响应内容编码，如果是gzip，需要使用特殊的gzip流对象来读取
			boolean gzip = "gzip".equalsIgnoreCase(conn.getContentEncoding());
			//保存响应类型
			param.setResponseContentType(conn.getContentType());
			//响应原始流
			InputStream inputStream = gzip ? new GZIPInputStream(conn.getInputStream()) : conn.getInputStream();
			//判断是否保存原始流
			if(param.isSaveAsStream()) {
				param.setInputStream(inputStream);
			}else {
				//创建读对象
				reader = new BufferedReader(new InputStreamReader(inputStream, param.getReceiveCode()));
				//开始读取数据
				String line;
				while ((line = reader.readLine()) != null) {
					sb.append(line);
				}
			}
		} catch (Exception e) {
			//抛出异常
			throw new UtilsException("发送"+Assert.getIfElse(post, "POST", "GET")+"请求出现异常！", e);
		}finally {
			//关闭资源
			IOUtils.closeQuietly(writer, reader);
		}
		//返回最终值
		return sb.length()==0 ? null : sb.toString();
	}

	/**
	 * 获取真实的IP地址
	 * @param request
	 * @return
	 */
	public static String getIpAddress(HttpServletRequest request){
		//判断内容为空的方式
		Function<String, Boolean> isEmpty = (ip)->ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip);
		//获取请求主机IP地址,如果通过代理进来，则透过防火墙获取真实IP地址  
		String ip = request.getHeader("X-Forwarded-For");
		//为空
		if(isEmpty.apply(ip)) {
			//为空标识
			boolean empty = false;
			//通过各种方式获取IP地址，直至找到IP地址为止
			for(String key: new String[] {"Proxy-Client-IP", "WL-Proxy-Client-IP", "HTTP_X_FORWARDED_FOR"}) {
				//获取IP，如果已经有值，则不再获取
				if((empty = isEmpty.apply(ip = request.getHeader(key)))) break;
			}
			if(empty) {
				ip = request.getRemoteAddr();
			}
		}else if(ip.length() > 15) {
			//遍历
			for(String tip: ip.split(",")) {
				//不等于unknown，则认为是IP
				if (!("unknown".equalsIgnoreCase(tip))) {
					ip = tip;break;
				}
			}
		}
		//返回IP
		return ip;
	}
}